//
//  EXTADT.h
//  extobjc
//
//  Created by Justin Spahr-Summers on 19.06.12.
//  Copyright (C) 2012 Justin Spahr-Summers.
//  Released under the MIT license.
//

#import "metamacros.h"
#import "EXTRuntimeExtensions.h"

/**
 * 创建一个或多个给定名称的数据类型的构造函数，每个构造函数都应该使用
 * constructor() 指定宏，其中第一个参数是构造函数名。0个或多个参数应该看起来
 * 像变量声明（例如“int x”）,可以跟在构造函数后面
 *
 * 其中，这可以有那个月创建类型安全的枚举，可以打印为字符串（并可选择与数据关联）
 *
 * 这个宏将创建：
 *
 * - 一个结构类型NameT，其中“Name”是这个宏的第一参数。该结构的每一个实例将包含一个成员“tag”，它是使用用于创建值的构造函数的枚举值来填充。
 * - 一个NSStringFromName()函数，它将ADT值转换为一个可读的字符串
 * -一个NameEqualToName()函数，它决定两个ADT值是否相等平等的。为了便于检查，对象使用isEqual:比较。
 *
 * - 对于每个构造函数
 *      - 一个枚举值Cons，可以用于引用该数据构造函数
 *      - 一个函数 Name.Cons(...)，它接受构造函数并且返回一个新的NameT结构
 *      - 每个构造函数的命名参数的成员属性，可以用来获取和设置与之相关的数据构造函数
 *
 * @code

// 这种调用方式:
ADT(Color,
    constructor(Red),
    constructor(Green),
    constructor(Blue),
    constructor(Gray, double alpha),
    constructor(Other, double r, double g, double b)
);

// 将会产生这样的结构定义:
typedef struct {
    enum { Red, Green, Blue, Gray, Other } tag;

    union {
        struct {
            double alpha;
        }

        struct {
            double r;
            double g;
            double b;
        }
    }
} ColorT;

NSString *NSStringFromColor (ColorT c);

ColorT Color.Red ();
ColorT Color.Green ();
ColorT Color.Blue ();
ColorT Color.Gray (double alpha);
ColorT Color.Other (double r, double g, double b);

 * @endcode
 *
 * @note ADT的构造函数中每个参数必须有一个在所有参数中都唯一的名称，所以点语法（例如：color.r）不需要在在名称前添加前缀（例如：color.hoter.r）
 *
 * @note 要定义递归类型，ADT参数可以执行已经被定义的类型的指针。例如：一个ADT参数Color是允许指向一个ColorT的指针
 *
 * @warning 访问与结构标记不对应的成员（例如 来自其他结构的参数数据）被认为是未定义的行为
 *
 * @bug 目前，只支持19个数据的构造函数，并且每个构造函数最多19个参数，这是由metamacro_foreach_cxt的限制
 *
 * @bug 一个ADT值嵌套在另一个ADT值中，当与生成的NSStringFrom…函数打印时可读性不是很好，所有其他数据将会是正常的
 */

/*
 #define ADT(NAME, ...)
 
    /// 使用行号和名称声明结构体并重命名为 nameT
     typedef struct ADT_CURRENT_T NAME ## T;

     metamacro_foreach_concat(ADT_typedef_,, __VA_ARGS__)
     struct ADT_CURRENT_T {
         const enum {
             metamacro_foreach_concat(ADT_enum_,, __VA_ARGS__)
         } tag;
         
         union {
             metamacro_foreach_concat(ADT_payload_,, __VA_ARGS__)
         };
     };
     
     metamacro_foreach_concat(ADT_,, __VA_ARGS__)
     
     const struct {
         metamacro_foreach_concat(ADT_fptrs_,, __VA_ARGS__)
     } NAME = {
         metamacro_foreach_concat(ADT_fptrinit_,, __VA_ARGS__)
     };
     
     static inline NSString *NSStringFrom ## NAME (NAME ## T s) {
         NSMutableString *str = [[NSMutableString alloc] init];
         
         BOOL addedBraces = NO;
         
         switch (s.tag) {
             metamacro_foreach_concat(ADT_tostring_,, __VA_ARGS__)
             default:
                 return nil;
         }
         
         if (addedBraces)
             [str appendString:@" }"];
         
         return str;
     }
     
     static inline BOOL NAME ## EqualTo ## NAME (NAME ## T a, NAME ## T b) {
         if (a.tag != b.tag)
             return NO;
         
         switch (a.tag) {
             metamacro_foreach_concat(ADT_equalto_,, __VA_ARGS__)
             default:
                 ;
         }
         
         return YES;
     }
 */

#define ADT(NAME, ...) \
    typedef struct ADT_CURRENT_T NAME ## T; \
    \
    metamacro_foreach_concat(ADT_typedef_,, __VA_ARGS__) \
    \
    struct ADT_CURRENT_T { \
        const enum { \
            metamacro_foreach_concat(ADT_enum_,, __VA_ARGS__) \
        } tag; \
        \
        union { \
            metamacro_foreach_concat(ADT_payload_,, __VA_ARGS__) \
        }; \
    }; \
    \
    metamacro_foreach_concat(ADT_,, __VA_ARGS__) \
    \
    const struct { \
        metamacro_foreach_concat(ADT_fptrs_,, __VA_ARGS__) \
    } NAME = { \
        metamacro_foreach_concat(ADT_fptrinit_,, __VA_ARGS__) \
    }; \
    \
    static inline NSString *NSStringFrom ## NAME (NAME ## T s) { \
        NSMutableString *str = [[NSMutableString alloc] init]; \
        \
        BOOL addedBraces = NO; \
        \
        switch (s.tag) { \
            metamacro_foreach_concat(ADT_tostring_,, __VA_ARGS__) \
            default: \
                return nil; \
        } \
        \
        if (addedBraces) \
            [str appendString:@" }"]; \
        \
        return str; \
    } \
    \
    static inline BOOL NAME ## EqualTo ## NAME (NAME ## T a, NAME ## T b) { \
        if (a.tag != b.tag) \
            return NO; \
        \
        switch (a.tag) { \
            metamacro_foreach_concat(ADT_equalto_,, __VA_ARGS__) \
            default: \
                ; \
        } \
        \
        return YES; \
    }

/*** implementation details follow ***/

/*
 * This macro simply creates an enum entry for the given constructor name.
 */
#define ADT_enum_constructor(...) \
    /* pop off the first variadic argument instead of using a named argument */ \
    /* (necessary because the ... in the argument list needs to match at least one argument) */ \
    metamacro_head(__VA_ARGS__),

/*
 * The "payload" terminology here refers to the data actually stored in an ADT
 * value, and more specifically to the data pertaining only to the constructor
 * that was used.
 *
 * These macros generate the internal layout of the NameT structure.
 *
 * For the following ADT:

ADT(Color,
    constructor(Red),
    constructor(Green),
    constructor(Blue),
    constructor(Gray, double alpha),
    constructor(Other, double r, double g, double b)
);

 * The resulting structure is laid out something like this:

typedef struct {
    const enum { Red, Green, Blue, Gray, Other } tag;

    union {
        // Gray
        struct {
            union {
                union {
                    double alpha;
                } Gray_payload_0;

                double alpha;
            };
        };

        // Other
        struct {
            union {
                union {
                    double r;
                } Other_payload_0;

                double r;
            };

            union {
                union {
                    double g;
                } Other_payload_1;

                double g;
            };

            union {
                union {
                    double b;
                } Other_payload_2;

                double b;
            };
        };
    };
} ColorT;

 * The use of anonymous structures and the containing anonymous union allows
 * a user to access parameter data without intervening steps (e.g.,
 * 'color.alpha', instead of 'color.Gray.alpha'), but does prevent two
 * parameters -- even for different constructors -- from having the same name.
 */
#define ADT_payload_constructor(...) \
    /* our first argument will always be the constructor name, so if we only
     * have one argument, we only have a constructor */ \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (/* this constructor has only a name, don't add any structures */)\
        ( \
            /* create structures for the parameters that exist */ \
            ADT_payload_constructor_(__VA_ARGS__) \
        )

#define ADT_payload_constructor_(CONS, ...) \
    struct { \
        metamacro_foreach_cxt_recursive(ADT_payload_entry_iter,, CONS, __VA_ARGS__) \
    };

#define ADT_payload_entry_iter(INDEX, CONS, PARAM) \
    ADT_CURRENT_CONS_UNION_T(CONS, INDEX, PARAM);

/*
 * The next few macros create type definitions for the unions used for each
 * parameter in the current ADT (e.g., those within the example structures
 * above).
 *
 * We do this so that instead of a type and name for each parameter (e.g.,
 * 'double alpha'), we can manipulate a union (e.g., 'Gray_payload_0') that
 * matches the type, but has a name we define.
 *
 * The type definitions are later used for function parameters created by
 * ADT_prototype_iter().
 */
#define ADT_typedef_constructor(...) \
    /* our first argument will always be the constructor name, so if we only
     * have one argument, we only have a constructor */ \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (/* no parameters, don't add any typedefs */) \
        ( \
            /* there are actually parameters */ \
            ADT_typedef_constructor_(__VA_ARGS__) \
        )

#define ADT_typedef_constructor_(CONS, ...) \
    metamacro_foreach_cxt_recursive(ADT_typedef_iter,, CONS, __VA_ARGS__)

#define ADT_typedef_iter(INDEX, CONS, PARAM) \
    typedef ADT_CURRENT_CONS_UNION_T(CONS, INDEX, PARAM) __attribute__((transparent_union)) \
        ADT_CURRENT_CONS_ALIAS_T(CONS, INDEX);

/*
 * This macro generates an inline function corresponding to one of the data
 * constructors, which will initialize an ADT value and return it.
 *
 * The first variadic argument here is always the name of the constructor, with
 * the rest of the argument list being the parameters given by the user.
 *
 * Unfortunately, we cannot give an argument name to the constructor, since
 * constructors may have no parameters, and the ... in the macro's argument list
 * needs to always match at least one argument. Instead, metamacro_head() is
 * used to get the constructor name.
 */
#define ADT_constructor(...) \
    static inline struct ADT_CURRENT_T \
    \
    /* the function name (e.g., 'Red_init_') */ \
    metamacro_concat(metamacro_head(__VA_ARGS__), _init_) \
    \
    /* the parameter list for this function */ \
    (metamacro_foreach_cxt_recursive(ADT_prototype_iter,, metamacro_head(__VA_ARGS__), __VA_ARGS__)) \
    { \
        /* the actual work of initializing the structure */ \
        /* the local variables for this function are defined in the first iteration of the loop */ \
        metamacro_foreach_cxt_recursive(ADT_initialize_iter,, metamacro_head(__VA_ARGS__), __VA_ARGS__) \
        return s; \
    }

/*
 * The macros below define each parameter to the constructor function.
 *
 * We use the type definitions created by ADT_typedef_iter() and give them
 * simple, sequentially-numbered names, so we don't have to do any more work to
 * parse or otherwise manipulate the declarations given by the user.
 *
 * Because the first argument to metamacro_foreach_recursive_cxt() is the
 * constructor name, our parameters actually need to be shifted down --
 * index 1 actually corresponds to v0, our first parameter.
 */
#define ADT_prototype_iter(INDEX, CONS, PARAM) \
    metamacro_if_eq(0, INDEX) \
        (/* the constructor name itself is passed as the first argument (again to
         * work around the caveat with variadic arguments), but we don't want it in
         * the parameter list, so we do nothing */) \
        ( \
            /* insert a comma for every argument after index 1 */ \
            metamacro_if_eq_recursive(1, INDEX)()(,) \
            \
            /* parameter type */ \
            ADT_CURRENT_CONS_ALIAS_T(CONS, metamacro_dec(INDEX)) \
            \
            /* parameter name */ \
            metamacro_concat(v, metamacro_dec(INDEX)) \
        )

/*
 * The macros below generate the initialization code that is actually executed
 * in the constructor function.
 *
 * We merely need to map the given arguments onto the internal unions defined by
 * ADT_payload_entry_iter(). Because the union is itself unioned with the
 * user-facing fields, the value can then be read by the user with the name they
 * gave it.
 *
 * As with ADT_prototype*(), our parameter numbers need to be shifted down to
 * correspond to the values in the structure.
 */
#define ADT_initialize_iter(INDEX, CONS, PARAM) \
    metamacro_if_eq(0, INDEX) \
        ( \
            /* initialize the tag when the structure is created, because it cannot change later */ \
            struct ADT_CURRENT_T s = { .tag = CONS } \
        ) \
        (ADT_initialize_memcpy(ADT_CURRENT_CONS_PAYLOAD_T(CONS, metamacro_dec(INDEX)), s, metamacro_concat(v, metamacro_dec(INDEX)))) \
    ;

#define ADT_initialize_memcpy(UNION_NAME, ADT, ARG) \
    memcpy(&ADT.UNION_NAME, &ARG.UNION_NAME, sizeof(ADT.UNION_NAME));

/*
 * The macros below declare and initialize the function pointers used to
 * psuedo-namespace the data constructors.
 *
 * As with ADT_constructor(), the first variadic argument here is always the
 * constructor name. The arguments following are the parameters (as given by the
 * user).
 *
 * The result looks something like this (using the Color example from above):

const struct {
    ColorT (*Red)();
    ColorT (*Green)();
    ColorT (*Blue)();
    ColorT (*Gray)(double v0);
    ColorT (*Other)(double v0, double v1, double v2);
} Color = {
    .Red = &Red_init_,
    .Green = &Green_init_,
    .Blue = &Blue_init_,
    .Gray = &Gray_init_,
    .Other = &Other_init_,
};

 * Thanks goes out to Jon Sterling and his CADT project for this idea:
 * http://www.jonmsterling.com/CADT/
 */
#define ADT_fptrs_constructor(...) \
    struct ADT_CURRENT_T \
    \
    /* the function pointer name (matches that of the constructor) */ \
    (*metamacro_head(__VA_ARGS__)) \
    \
    /* the parameter list for the function -- we just reuse ADT_prototype_iter() for this */ \
    (metamacro_foreach_cxt_recursive(ADT_prototype_iter,, metamacro_head(__VA_ARGS__), __VA_ARGS__));

#define ADT_fptrinit_constructor(...) \
    /* this uses designated initializer syntax to fill in the function pointers
     * with the actual addresses of the inline functions created by ADT_constructor() */ \
    .metamacro_head(__VA_ARGS__) = &metamacro_concat(metamacro_head(__VA_ARGS__), _init_),

/*
 * The following macros are used to generate the code for the
 * NSStringFromName() function. They essentially do something similar to
 * an Objective-C implementation of -description.
 *
 * As with ADT_constructor(), the first variadic argument here is always the
 * constructor name. The arguments following are the parameters (as given by the
 * user).
 *
 * As with ADT_prototype*(), our parameter numbers need to be shifted down to
 * correspond to the values in the structure.
 */
#define ADT_tostring_constructor(...) \
        /* try to match each constructor against the value's tag */ \
        case metamacro_head(__VA_ARGS__): { \
            /* now create a description from the constructor name and any parameters */ \
            metamacro_foreach_cxt_recursive(ADT_tostring_iter,, metamacro_head(__VA_ARGS__), __VA_ARGS__) \
            break; \
        }

#define ADT_tostring_iter(INDEX, CONS, PARAM) \
    /* dispatches to one of the case macros below, based on the INDEX */ \
    metamacro_if_eq(0, INDEX) \
        (ADT_tostring_case0(CONS, PARAM)) \
        (metamacro_if_eq_recursive(1, INDEX) \
            (ADT_tostring_case1(CONS, PARAM)) \
            (ADT_tostring_defaultcase(INDEX, CONS, PARAM)) \
        )

#define ADT_tostring_case0(CONS, PARAM) \
    /* this is the first (and possibly) only part of the description: the name
     * of the data constructor */ \
    [str appendString:@ # CONS];

#define ADT_tostring_case1(CONS, PARAM) \
    /* we know now that we have arguments, so we insert a brace (and flip the
     * corresponding flag), then begin by describing the first argument */ \
    [str appendFormat:@" { %@", ADT_CURRENT_PARAMETER_DESCRIPTION(CONS, PARAM, s, 0)]; \
    addedBraces = YES;

#define ADT_tostring_defaultcase(INDEX, CONS, PARAM) \
    [str appendFormat: @", %@", ADT_CURRENT_PARAMETER_DESCRIPTION(CONS, PARAM, s, metamacro_dec(INDEX))];

/*
 * The following macros are used to generate the code for the
 * NameEqualToName() function. They essentially do something similar to
 * an Objective-C implementation of -isEqual:.
 *
 * As with ADT_constructor(), the first variadic argument here is always the
 * constructor name. The arguments following are the parameters (as given by the
 * user).
 *
 * As with ADT_prototype*(), our parameter numbers need to be shifted down to
 * correspond to the values in the structure.
 */
#define ADT_equalto_constructor(...) \
        /* try to match each constructor against the value's tag */ \
        case metamacro_head(__VA_ARGS__): { \
            metamacro_if_eq(1, metamacro_argcount(...)) \
                (/* no parameters, so we're equal merely if the tags are the same */) \
                (metamacro_foreach_cxt_recursive(ADT_equalto_iter,, __VA_ARGS__)) \
            \
            break; \
        }

#define ADT_equalto_iter(INDEX, CONS, PARAM) \
    { \
        const char *paramEncoding = ext_trimADTJunkFromTypeEncoding(@encode(ADT_CURRENT_CONS_ALIAS_T(CONS, INDEX)); \
        \
        /* use isEqual: for objects (including class objects) */ \
        if (*paramEncoding == *@encode(id) || *paramEncoding == *@encode(Class)) { \
            id aObj = *(__unsafe_unretained id *)&a.ADT_CURRENT_CONS_PAYLOAD_T(CONS, INDEX); \
            id bObj = *(__unsafe_unretained id *)&b.ADT_CURRENT_CONS_PAYLOAD_T(CONS, INDEX); \
            \
            if (!aObj) { \
                if (bObj) { \
                    return NO; \
                } \
            } else if (![aObj isEqual:bObj]) { \
                return NO; \
            } \
        } else { \
            /* prefer == to memcmp() here, since ADT values may have garbage padding
             * bits that would cause false negatives with the latter */ \
            if (a.ADT_CURRENT_CONS_PAYLOAD_T(CONS, INDEX) != b.ADT_CURRENT_CONS_PAYLOAD_T(CONS, INDEX)) \
                return NO; \
        } \
    }

/*
 * 当前正在定义的结构体标记，这利用主ADT（）存在的当前行，虽然它跨越编辑器中的多行
 *
 * 这阻止了相同行定义多个ADT()的问题
 */
#define ADT_CURRENT_T \
    metamacro_concat(_ADT_, __LINE__)

/*
 * This generates an alias name that can be used to refer to the type of
 * parameter INDEX of constructor CONS (as a transparent union).
 *
 * The actual typedef, which is then referred to later, is generated with
 * ADT_typedef_iter().
 *
 * Because the type by this name is a transparent union, it can be used as
 * a function or method argument and appear to be the actual parameter type
 * given by the user.
 */
#define ADT_CURRENT_CONS_ALIAS_T(CONS, INDEX) \
    metamacro_concat(metamacro_concat(ADT_CURRENT_T, _), metamacro_concat(CONS ## _alias, INDEX))

/**
 * Creates an anonymous union that contains the user's parameter declaration as
 * a member, as well as an (other) internal union that is used to access the
 * data without needing to know the name given by the user.
 *
 * See ADT_payload_constructor() for more information.
 */
#define ADT_CURRENT_CONS_UNION_T(CONS, INDEX, PARAM) \
    /* create unions upon unions (oh my!) so that we can treat the user's
     * parameter as a typedef, without needing to split apart the type and name
     * inside it (which is probably not possible) */ \
    union { \
        union { \
            PARAM; \
        } ADT_CURRENT_CONS_PAYLOAD_T(CONS, INDEX); \
        \
        PARAM; \
    }

#define ADT_CURRENT_CONS_PAYLOAD_T(CONS, INDEX) \
    metamacro_concat(CONS ## _payload_, INDEX)

/*
 * Expands to an NSString with a human-readable description of the current value
 * at INDEX, for constructor CONS, in the internal value structure of ADT. PARAM
 * is the parameter declaration originally given by the user.
 */
#define ADT_CURRENT_PARAMETER_DESCRIPTION(CONS, PARAM, ADT, INDEX) \
    [NSString stringWithFormat:@"%@ = %@", \
        /* this is the only place where we actually parse a parameter declaration */ \
        /* we do it here to remove the type from the description, keeping only the name */ \
        ext_parameterNameFromDeclaration(@ # PARAM), \
        /* convert the parameter type into an Objective-C type encoding, which,
         * along with a pointer to the data, can be used to generate
         * a human-readable description of the actual value */ \
        ext_stringFromTypedBytes(&(ADT).ADT_CURRENT_CONS_PAYLOAD_T(CONS, INDEX), \
            ext_trimADTJunkFromTypeEncoding(@encode(ADT_CURRENT_CONS_ALIAS_T(CONS, INDEX)))) \
    ]

const char *ext_trimADTJunkFromTypeEncoding (const char *encoding);
NSString *ext_parameterNameFromDeclaration (NSString *declaration);
